/* Orbas Naming Server:
 *     A open source CORBA CosNaming implementation from Huihoo.
 *
 * Copyright 2003 Huihoo Power, Inc. All Right Reserved.
 *
 * This software is licensed under LGPL license.
 * See terms of license at gnu.org.
 *
 * For more information, visit:
 *
 * http://www.huihoo.org/orbas
 */
package org.huihoo.orbas.naming;
/**
 * <p>Description: </p>
 * Namingcontext Implemention.
 * <p>Copyright (c) 2003</p>
 * <p>Company: <a href="http://www.huihoo.org/orbas">huihoo.org</a></p>
 * @author <a href="http://www.huihoo.org/~cocia">Cocia Lin(cocia@163.com)</a>
 * @see <a href="http://www.huihoo.org/orbas">http://www.huihoo.org/orbas</a>
 * @version 1.0
 */

import org.omg.CORBA.Object;
import org.omg.CORBA.*;
//import org.omg.CORBA_2_5.ORB;
import org.omg.PortableServer.POA;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextExtPackage.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.huihoo.orbas.naming.util.*;
import java.util.*;
import org.huihoo.orbas.naming.util.*;

public class NamingContextExtImpl
    extends NamingContextExtPOA {
    /**
     * Private Section.
     */
    //
    private Hashtable names = new Hashtable();
    private Hashtable contexts = new Hashtable();
    //orb and poa reference.
    ORB orb;
    POA poa;
    POA rootPoa;
    //record the children number of this.
    private int child_count = 0;
    /**
        roseuid 3E8D3C4401FB
     */
    public NamingContextExtImpl(ORB orb, POA poa) {
        this.orb = orb;
        this.poa = poa;
        //
        try {
            //Get the RootPOA.
            this.rootPoa =
                org.omg.PortableServer.POAHelper.narrow(
                orb.resolve_initial_references("RootPOA"));
        }
        catch (org.omg.CORBA.ORBPackage.InvalidName in) {
            in.printStackTrace();
        }

    }

    /**
        @param n
        @return String
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        roseuid 3E8A61A1032C
     */
    public String to_string(NameComponent[] n) throws InvalidName {
        //Valid the parameter.
        if (n == null || n.length == 0) {
            throw new InvalidName();
        }
        /*
        StringBuffer name = new StringBuffer();
        String sepertor1 = "/";
        String sepertor2 = ".";
        for (int i = 0; i < n.length; i++) {
            NameComponent nc = n[i];
            if (i > 0) {
                name.append(sepertor1);
            }
            //
            name.append(nc.id);
            if (nc.kind != null) {
                name.append(sepertor2);
            }
        }*/
        return Name.toString(n);
    }

    /**
        @param sn
        @return org.omg.CosNaming.NameComponent[]
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        roseuid 3E8A61A1034B
     */
    public NameComponent[] to_name(String sn) throws InvalidName {
        if (sn == null || sn.length() == 0) {
            throw new InvalidName();
        }
        return Name.toName(sn);
    }

    /**
        @param addr
        @param sn
        @return String
        @throws org.omg.CosNaming.NamingContextExtPackage.InvalidAddress
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        roseuid 3E8A61A1036B
     */
    public String to_url(String addr, String sn) throws InvalidAddress,
        InvalidName {
        CorbaLoc corbaLoc;
        try
        {
            corbaLoc = new CorbaLoc( addr );
            return corbaLoc.toCorbaName( sn );
        }
        catch( IllegalArgumentException ia )
        {
            throw new InvalidAddress();
        }

    }

    /**
        @param sn
        @return org.omg.CORBA.Object
        @throws org.omg.CosNaming.NamingContextPackage.NotFound
        @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        roseuid 3E8A61A10399
     */
    public Object resolve_str(String sn) throws NotFound, CannotProceed,
        InvalidName {
        NameComponent[] nc = to_name(sn);
        return resolve( nc );
    }

    /**
        @throws org.omg.CosNaming.NamingContextPackage.NotEmpty
        roseuid 3E8A61A103B9
     */
    public void destroy() throws NotEmpty {

    }

    /**
        @param nc
        @param obj
        @throws org.omg.CosNaming.NamingContextPackage.NotFound
        @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        @throws org.omg.CosNaming.NamingContextPackage.AlreadyBound
        roseuid 3E8A61A103C8
     */
    public void bind(NameComponent[] nc, Object obj) throws NotFound,
        CannotProceed, InvalidName, AlreadyBound {

        if( nc == null || nc.length == 0 )
            throw new InvalidName();

        if( obj == null )
            throw new org.omg.CORBA.BAD_PARAM();

        Name n = new Name( nc );
        Name ctx = n.ctxName();
        NameComponent nb = n.baseNameComponent();
        if( ctx == null )
        {
            if( names.containsKey( n ))
            {
                // if the name is still in use, try to ping the object
                org.omg.CORBA.Object s = (org.omg.CORBA.Object)names.get(n);
                if( s._non_existent() )
                {
                    rebind( n.components(), obj );
                    return;
                }
                throw new AlreadyBound();
            }
            else if( contexts.containsKey( n ))
            {
                // if the name is still in use, try to ping the object
                org.omg.CORBA.Object s = (org.omg.CORBA.Object)contexts.get(n);
                if( s._non_existent() )
                {
                    unbind( n.components());
                }
                throw new AlreadyBound();
            }

            if(( names.put( n, obj )) != null )
                throw new CannotProceed( _this(), n.components() );
            System.out.println("Bound name: " + n.toString());

        }
        else
        {
            NameComponent[] ncx = new NameComponent[1];
            ncx[0] = nb;
            NamingContextExtHelper.narrow(resolve(ctx.components())).bind(ncx,obj);
        }

    }

    /**
        @param n
        @param nc
        @throws org.omg.CosNaming.NamingContextPackage.NotFound
        @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        @throws org.omg.CosNaming.NamingContextPackage.AlreadyBound
        roseuid 3E8A61A2000F
     */
    public void bind_context(NameComponent[] nc, NamingContext obj) throws
        NotFound, CannotProceed, InvalidName, AlreadyBound {
        Name n = new Name( nc );
        Name ctx = n.ctxName();
        NameComponent nb = n.baseNameComponent();

        if( ctx == null )
        {
            if( names.containsKey( n ))
            {
                // if the name is still in use, try to ping the object
                org.omg.CORBA.Object s = (org.omg.CORBA.Object)names.get(n);
                if( s._non_existent() )
                {
                    unbind( n.components());
                }
                else
                    throw new AlreadyBound();
            }
            else if( contexts.containsKey( n ))
            {
                // if the name is still in use, try to ping the object
                org.omg.CORBA.Object s = (org.omg.CORBA.Object)contexts.get(n);
                if( s._non_existent() )
                {
                    rebind_context( n.components(), obj );
                    return;
                }
                throw new AlreadyBound();
            }

            if( (contexts.put( n, obj )) != null )
                throw new CannotProceed( _this(), n.components());
            contexts.put( n, obj );

            System.out.println("Bound context: " + n.toString());
        }
        else
        {
            NameComponent[] ncx = new NameComponent[1];
            ncx[0] = nb;
            NamingContextExtHelper.narrow(resolve(ctx.components())).bind_context(ncx,obj);
        }

    }

    /**
        @param n
        @param obj
        @throws org.omg.CosNaming.NamingContextPackage.NotFound
        @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        roseuid 3E8A61A2004E
     */
    public void rebind(NameComponent[] nc, Object obj) throws NotFound,
        CannotProceed, InvalidName {

        if( nc == null || nc.length == 0 )
            throw new InvalidName();

        if( obj == null )
            throw new org.omg.CORBA.BAD_PARAM();

        Name n = new Name( nc );
        Name ctx = n.ctxName();
        NameComponent nb = n.baseNameComponent();

        // the name is bound, but it is bound to a context,
        // the client should have been using rebind_context!

        if( contexts.containsKey( n ))
            throw new NotFound(NotFoundReason.not_object, new NameComponent[]{ nb } );

        // try remove an existing binding

        org.omg.CORBA.Object _o = (org.omg.CORBA.Object)names.remove( n );
        if( _o != null)
            _o._release();

        if( ctx == null )
        {
            // do the rebinding in this context

            names.put( n, obj );
            System.out.println("Re-bound name: " + n.toString());
        }
        else
        {
            // rebind in the correct context

            NameComponent[] ncx = new NameComponent[1];
            ncx[0] = nb;
            NamingContextExt nce = NamingContextExtHelper.narrow(resolve(ctx.components()));
            if( nce == null )
                throw new CannotProceed();
            nce.rebind(ncx,obj);
        }

    }

    /**
        @param n
        @param nc
        @throws org.omg.CosNaming.NamingContextPackage.NotFound
        @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        roseuid 3E8A61A2008C
     */
    public void rebind_context(NameComponent[] nc, NamingContext obj) throws
        NotFound, CannotProceed, InvalidName {
        if( nc == null || nc.length == 0 )
            throw new InvalidName();

        if( obj == null )
            throw new org.omg.CORBA.BAD_PARAM();

        Name n = new Name( nc );
        Name ctx = n.ctxName();
        NameComponent nb = n.baseNameComponent();

        // the name is bound, but it is bound to an object,
        // the client should have been using rebind() !

        if( names.containsKey( n ))
            throw new NotFound(NotFoundReason.not_context,new NameComponent[]{ nb });

        // try to remove an existing context binding

        org.omg.CORBA.Object _o = (org.omg.CORBA.Object)contexts.remove( n );
        if( _o != null)
            _o._release();

        if( ctx == null )
        {
            contexts.put( n, obj );
            System.out.println("Re-Bound context: " +
                                     n.baseNameComponent().id);
        }

    }

    /**
        @param n
        @return org.omg.CORBA.Object
        @throws org.omg.CosNaming.NamingContextPackage.NotFound
        @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        roseuid 3E8A61A200CB
     */
    public Object resolve(NameComponent[] nc) throws NotFound, CannotProceed,
        InvalidName {
        if( nc == null || nc.length == 0 )
            throw new InvalidName();

        Name n = new Name( nc[0] );
        if( nc.length > 1 )
        {
            NamingContextExt next_context =
                NamingContextExtHelper.narrow((org.omg.CORBA.Object)contexts.get(n));

            if ((next_context == null)||(next_context._non_existent()))
            {
                throw new NotFound(NotFoundReason.missing_node,nc);
            }

            NameComponent[] nc_prime =
                new NameComponent[nc.length-1];

            for( int i = 1; i < nc.length; i++)
                nc_prime[i-1] = nc[i];

            return next_context.resolve(nc_prime);
        }
        else
        {
            org.omg.CORBA.Object result = null;

            result = (org.omg.CORBA.Object)contexts.get(n);

            if( result == null )
                result = (org.omg.CORBA.Object)names.get(n);

            if( result == null || result._non_existent())
                throw new NotFound(NotFoundReason.missing_node, n.components());

            return result;
        }

    }

    /**
        @param n
        @throws org.omg.CosNaming.NamingContextPackage.NotFound
        @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        roseuid 3E8A61A200EA
     */
    public void unbind(NameComponent[] nc) throws NotFound, CannotProceed,
        InvalidName {

        if( nc == null || nc.length == 0 )
            throw new InvalidName();

        Name n = new Name( nc );
        Name ctx = n.ctxName();
        NameComponent nb = n.baseNameComponent();

        if( ctx == null )
        {
            if( names.containsKey(n))
            {
                org.omg.CORBA.Object o = (org.omg.CORBA.Object)names.remove( n );
                o._release();
                System.out.println("Unbound: " + n.toString());
            }
            else if( contexts.containsKey(n))
            {
                org.omg.CORBA.Object o = (org.omg.CORBA.Object)contexts.remove( n );
                o._release();
                System.out.println("Unbound: " + n.toString());
            }
            else
            {
                System.out.println("Unbind failed for " + n.toString() );
                throw new NotFound(
                                   NotFoundReason.not_context,
                                   n.components());
            }
        }
        else
        {
            NameComponent[] ncx = new NameComponent[1];
            ncx[0] = nb;
            NamingContextExtHelper.narrow( resolve( ctx.components())).unbind(ncx );
        }

    }
    private int how_many()
    {
        return names.size() + contexts.size();
    }

    /**
        @param how_many
        @param bl
        @param bi
        roseuid 3E8A61A20119
     */
    public void list(int how_many, BindingListHolder bl,
                     BindingIteratorHolder bi) {
        Binding[] result;

        int size = how_many();

        Enumeration n = names.keys();
        Enumeration c = contexts.keys();

        if( how_many < size )
        {
            // counter for copies
            int how_many_ctr = how_many;

            // set up an array with "how_many" bindings

            result = new Binding[how_many];
            for( ; n.hasMoreElements() && how_many_ctr > 0; how_many_ctr-- )
            {
                result[how_many_ctr-1] = new Binding(((Name)n.nextElement()).components(),
                                                 BindingType.nobject );
            }

            for( ; c.hasMoreElements() && how_many_ctr > 0; how_many_ctr-- )
            {
                result[how_many_ctr-1] = new Binding(((Name)c.nextElement()).components(),
                                                 BindingType.ncontext);
            }

            // create a new BindingIterator for the remaining arrays

            size -= how_many;
            Binding[] rest = new Binding[ size ];
            for( ; n.hasMoreElements() && size > 0; size-- )
            {
                rest[size-1] = new Binding(((Name)n.nextElement()).components(),
                                           BindingType.nobject );
            }

            for( ; c.hasMoreElements() && size > 0; size-- )
            {
                rest[size-1] = new Binding(((Name)c.nextElement()).components(),
                                           BindingType.ncontext);
            }

            org.omg.CORBA.Object o = null;
            try
            {
                // Iterators are activated with the RootPOA (transient)
                byte[] oid = rootPoa.activate_object( new BindingIteratorImpl( rest ) );
                o = rootPoa.id_to_reference(oid);
            }
            catch ( Exception ue )
            {
                ue.printStackTrace();
            }

            bi.value = BindingIteratorHelper.narrow(o);
        }
        else
        {
            result = new Binding[size];
            for( ; n.hasMoreElements() && size > 0; size-- )
            {
                result[size-1] =
                    new Binding(((Name)n.nextElement()).components(),
                                BindingType.nobject );
            }

            for( ; c.hasMoreElements() && size > 0; size-- )
            {
                result[size-1] =
                    new Binding(((Name)c.nextElement()).components(),
                                BindingType.ncontext);
            }
        }

        bl.value = result;

    }

    /**
        @return org.omg.CosNaming.NamingContext
        roseuid 3E8A61A20167
     */
    public NamingContext new_context() {
        org.omg.CORBA.Object ctx = null;
        try
        {
            byte[] oid = (new String(poa.servant_to_id(this)) +
                          "_ctx" + (++child_count)).getBytes();

            ctx = poa.create_reference_with_id( oid, "IDL:omg.org/CosNaming/NamingContextExt:1.0");
        }
        catch ( Exception ue )
        {
            ue.printStackTrace();
            System.exit(1);
        }
        return NamingContextExtHelper.narrow(ctx);

    }

    /**
        @param n
        @return org.omg.CosNaming.NamingContext
        @throws org.omg.CosNaming.NamingContextPackage.NotFound
        @throws org.omg.CosNaming.NamingContextPackage.AlreadyBound
        @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
        @throws org.omg.CosNaming.NamingContextPackage.InvalidName
        roseuid 3E8A61A20177
     */
    public NamingContext bind_new_context(NameComponent[] nc) throws NotFound,
        AlreadyBound, CannotProceed, InvalidName {
        if( nc == null || nc.length == 0 )
            throw new InvalidName();

        NamingContextExt ns = NamingContextExtHelper.narrow(new_context());
        bind_context( nc, ns );

        if( ns == null )
        {
            throw new CannotProceed();
        }
        return ns;

    }

}
